package com.cxd.app.service;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.cxd.app.constants.PublicConstants;
import com.cxd.app.entity.AppLoan;
import com.cxd.app.entity.Invest;
import com.cxd.app.entity.InvestInfo;
import com.cxd.app.entity.InvestRecord;
import com.cxd.app.entity.Loan;
import com.cxd.app.entity.RepayRoadmap;
import com.cxd.app.entity.WdzjInvest;
import com.cxd.app.entity.WdzjLoan;
import com.cxd.app.entity.base.InvestBase;
import com.cxd.app.entity.base.InvestRepayBase;
import com.cxd.app.entity.base.LoanBase;
import com.cxd.app.entity.base.LoanTypeBase;
import com.cxd.app.entity.base.NodeBase;
import com.cxd.app.entity.base.NodeBodyBase;
import com.cxd.app.entity.base.TrusteeshipOperationBase;
import com.cxd.app.entity.base.UserBase;
import com.cxd.app.mapper.read.RInvestMapper;
import com.cxd.app.mapper.read.RLoanMapper;
import com.cxd.app.tools.LoanTools;
import com.cxd.base.common.constants.InvestConstants;
import com.cxd.base.common.constants.InvestConstants.InvestStatus;
import com.cxd.base.common.constants.LoanConstants;
import com.cxd.base.common.constants.LoanConstants.LoanStatus;
import com.cxd.base.common.constants.RepayConstants;
import com.cxd.base.common.constants.YeePayConstants;
import com.cxd.base.common.exception.CxdException;
import com.cxd.base.common.exception.VersionException;
import com.cxd.base.page.PageUtil;
import com.cxd.base.page.tag.TagPage;
import com.cxd.base.util.ArithUtil;
import com.cxd.base.util.BeanTools;
import com.cxd.base.util.CxdStringUtil;
import com.cxd.base.util.HtmlElementUtil;
import com.cxd.base.util.IdGenerator;
import com.cxd.base.util.MapUtil;
import com.cxd.base.util.NumberUtil;
import com.cxd.base.util.ParamUtil;
import com.cxd.base.util.ProjecConfig;
import com.cxd.base.util.date.DateStyle;
import com.cxd.base.util.date.DateUtil;
import com.cxd.base.util.sql.SqlInUtil;
import com.cxd.base.util.wtj.BUtils;
import com.cxd.message.exception.AppConstants;
import com.cxd.message.exception.CFCASignUtil;
import com.cxd.message.exception.ExceedDeadlineException;
import com.cxd.message.exception.ExceedMaxAcceptableRate;
import com.cxd.message.exception.ExceedMoneyNeedRaised;
import com.cxd.message.exception.IllegalLoanStatusException;
import com.cxd.message.exception.InsufficientBalance;
import com.cxd.message.exception.NewStandardNotException;
import com.cxd.message.exception.TrusteeshipConstants;
import com.cxd.message.exception.UnreachedMoneyLimitException;

/**
 * <一句话功能简述> <功能详细描述>
 * 
 * @author wtj
 * @date 2015年12月4日 下午3:00:39
 * @company CXD
 * @version [Copyright (c) 2015 V001]
 */
@Service("loanService")
public class LoanService {
	
	private static final Logger logger = Logger.getLogger(LoanService.class);
	
	private final String NEWER_LOAN_BEGIN = "2016-03-01 00:00:00";
	@Resource
	public BeanTools bt;

	@Resource
	public RLoanMapper rloanMapper;

	@Resource
	public RInvestMapper rinvestMapper;

	@Resource
	public MyAccountService myaccountService;

	@Resource
	public InvestService investService;

	@Resource
	public DictService dictService;

	@Resource
	public TrusteeshipOperationService trusteeshipOperationService;

	@Resource
	public BeanService beanService;
	
	public static LoanTools loanTools = new LoanTools();
	
	

	/**
	 * 获取标详情
	 * 
	 * @author wtj
	 * @date 2015年12月23日下午4:48:11
	 * @param json
	 * @param value
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	public void loan(JSONObject json, String value)
			throws InstantiationException, IllegalAccessException {
		Map<String, Object> param = MapUtil.jsonToMap(value);
		String loanId = param.get("loanId").toString();
		ParamUtil.notNullParam("loanId:"+loanId);
		LoanBase loan = beanService.getLoanById(loanId);
		
		AppLoan appLoan = new AppLoan(loan,bt,2);
		loadLoanByLoanId(loan,appLoan);
		json.put("result", appLoan == null ? new String[] {} : appLoan);
	}

	/**
	 * 获取项目列表
	 * 
	 * @author wtj
	 * @param json
	 * @param value
	 *            { pageSize, currentPage, rate 年化利率范围起始 deadline 项目期限范围起始时间
	 *            timeUnit 项目期限单位 status 项目状态
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 */
	public void loans(JSONObject json, String value)
			throws InstantiationException, IllegalAccessException {
		Map<String, Object> param = MapUtil.jsonToMap(value);
		Object pageSize = param.get("pageSize");
		Object currentPage = param.get("currentPage");
		if (pageSize == null || currentPage == null) {
			throw new CxdException("分页信息不能为空");
		}
		TagPage page = PageUtil.getTagPage(currentPage.toString(),pageSize.toString());
		param.put("page", page);
		
		Long beginTime = System.currentTimeMillis();
		List<Map<String,Object>> list = rloanMapper.loansListPage(param);
		Long endTime = System.currentTimeMillis();
		logger.info("获取数据时长:------"+(beginTime-endTime));
		
		List<LoanBase> listLoan = BUtils.tableListMapToBean(list, LoanBase.class);
		Long zhTime = System.currentTimeMillis();
		logger.info("获取转换时长:------"+(endTime-zhTime));
		
		List<AppLoan> appLoans = new ArrayList<AppLoan>();
		AppLoan appLoan;
		for (LoanBase loan : listLoan) {
			appLoan = new AppLoan(loan,bt,2);
			this.loadLoanByLoanId(loan,appLoan);
			appLoans.add(appLoan);
		}
		json.put("result", appLoans.size() == 0 ? new String[] {} : appLoans);
	}

	/**
	 * 获取项目详情
	 * 
	 * @author wtj
	 * @date 2015年12月5日下午5:37:04
	 * @param loan
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	private void loadLoanByLoanId(LoanBase loan,AppLoan appLoan)
			throws InstantiationException, IllegalAccessException {
		Double progress = ArithUtil.round(loadalreadyInvestMoney(loan.getId()) * 100/ loan.getLoanMoney(), 2,BigDecimal.ROUND_DOWN);
		if(progress>100){
			progress = 100d;
		}
		appLoan.setProgress(progress+"");
		long syTime = loan.getExpectTime().getTime()
				- loan.getCommitTime().getTime();
		appLoan.setRemainTime(loanTools.formatDuring(syTime));
		// 投资剩余金额
		appLoan.setRemainMoney(remainMoney(loan) + "");
		appLoan.setStatus(loan.getStatus());

		// if (LoanConstants.LoanStatus.RECHECK.equals(loan.getStatus())) {
		// appLoan.setStatus("复核中");
		// } else if
		// (LoanConstants.LoanStatus.COMPLETE.equals(loan.getStatus())) {
		// appLoan.setStatus("已完成");
		// } else if (LoanConstants.LoanStatus.RAISING.equals(loan.getStatus()))
		// {
		// appLoan.setStatus("投标中");
		// } else if
		// (LoanConstants.LoanStatus.REPAYING.equals(loan.getStatus())) {
		// appLoan.setStatus("还款中");
		// }

		LoanTypeBase loanType = this.queryLoanTypeByType(loan.getType());
		if (RepayConstants.RepayUnit.DAY.equals(loanType.getRepayTimeUnit())) {
			appLoan.setUnit("天");
		} else if (RepayConstants.RepayUnit.MONTH.equals(loanType
				.getRepayTimeUnit())) {
			appLoan.setUnit("月");
		}
	}

	/**
	 * 获取新手标
	 * 
	 * @author wtj
	 * @date 2015年12月5日下午2:00:37
	 * @param json
	 * @param value
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	public void loadNewerLoan(JSONObject json, String value)
			throws InstantiationException, IllegalAccessException {
		Map<String, Object> param = MapUtil.jsonToMap(value);
		Object userId = param.get("userId");
		// 验证数据不能为空
		// ParamUtil.notNullParam("userId:"+userId);
//		String sql = "SELECT * FROM LOAN where deadline=8 and rate=0.2 "
//				+ "and status in ('raising','recheck','repaying','complete') and COMMIT_TIME>'"
//				+ PublicConstants.NEWER_BEGIN_TIME
//				+ "'"
//				+ "ORDER BY field(status,'raising','recheck','repaying','complete') asc,seq_num desc,id asc limit 0,100";
		
		// 查询新手标
		String sql = "select * from loan where deadline='8' and status = 'raising' and  rate = 0.2 ORDER BY commit_time desc limit 0,4";
		// + " union select *, 2 ind from loan where deadline!='8'  and status = 'raising'  ORDER BY  deadline=6 asc , deadline desc,seq_num desc ,id asc LIMIT 0,10"
		
		// 用户已经登录
		if(userId!=null){
			// 用户已经投资过新手标
			if(this.getUserNewLoanCount(userId)>0){
				sql = "select * from ( "+
					  "		select *,0 ind from loan where status = 'raising' and  deadline='8' and rate != 0.2 "+
					  "			union "+
					  "		select *, (case deadline when 5 then 1 when 6 then 2 when 4 then 3 when 3 then 4 when 2 then 5  when 1 then 6 else 7 end) as  ind "+
					  "			from loan where status = 'raising'  LIMIT 0,5"+
					  "	) t1 order by t1.ind ";
			}
		}
		List<LoanBase> loanList = bt.queryListBean(sql, LoanBase.class);
		AppLoan appLoan = new AppLoan();
		for(LoanBase lo:loanList){
			appLoan = new AppLoan(lo,bt,2);
			this.loadLoanByLoanId(lo,appLoan);
			if(Double.parseDouble(appLoan.getProgress())!=100){
				break;
			}
		}
		
		// 未获取到有效的新手标
		if(appLoan.getId()==null){
			if(userId==null){
				sql = "select * from loan where status in ('complete','repaying','raising') and deadline='8' and rate = 0.2 ORDER BY loan.commit_time desc LIMIT 1";
			}else{
				// 投资过新手标
				if(this.getUserNewLoanCount(userId)>0){
					sql = "select * from loan where status in ('complete','repaying','raising') and deadline='8' and rate != 0.2 ORDER BY loan.commit_time desc LIMIT 1";
				}
				// 未投资过新手标
				else{
					sql = "select * from loan where status in ('complete','repaying','raising') and deadline='8' and rate = 0.2 ORDER BY loan.commit_time desc LIMIT 1";
				}
			}
			LoanBase lb = bt.queryBean(sql, LoanBase.class);
			appLoan = new AppLoan(lb,bt,2);
			this.loadLoanByLoanId(lb,appLoan);
		}
		Map<String, Object> map = BUtils.beanToMap(appLoan);
		
		// 借款金额单位转换为万元
		// long syTime = loan.getExpectTime().getTime()-
		// loan.getCommitTime().getTime();
		// LoanTools loanTools = new LoanTools();
		// 用于剩余天数
		// map.put("loanSYTime", loanTools.formatDuring(syTime));
		// 标状态
		// map.put("dictLoanStatus",loanTools.getDictLoanStatus().get(loan.getStatus()));
		// map.put("loanTZProgress", loanCompletedRate(loan));
		map.put("newerLoanTip", loadUserNewerLoanTip(userId == null ? "": userId.toString()));
		json.put("result", map);
	}

	/**
	 * 个人投资
	 * 
	 * @author wtj
	 * @date 2015年12月7日下午3:37:21
	 * @param json
	 * @param value
	 */
	@Transactional(propagation = Propagation.REQUIRED)
	public void invest(JSONObject json, String value)throws VersionException {
		try {
			@SuppressWarnings("unchecked")
			Map<String, String> param = JSON.parseObject(value, HashMap.class);
			String userId = param.get("userId");// 用户编号
			String loanId = param.get("loanId");// 项目编号
			String investMoney = param.get("investMoney");// 投资金额
			// 验证数据不允许为空
			ParamUtil.notNullParam("用户ID:" + userId, "loanId:" + loanId,
					"investMoney:" + investMoney);
			LoanBase loan = beanService.getLoanById(loanId);
			if (!LoanStatus.RAISING.equals(loan.getStatus())) {
				throw new CxdException("该项目不处于可投资状态");
			}
			if (loanCompletedRate(loan) >= 100) {
				throw new CxdException("该项目已投满");
			}
			// 判断项目尚未认购的金额，如果用户想认购的金额大于此金额，则。。。
			double remainMoney = remainMoney(loan);
			double investMoneyd = Double.parseDouble(investMoney);
			
			if(loan.getDeadline().equals("8")&&loan.getRate()==0.2){
				if(this.isCanInvest(userId)){
					if(getUserNewLoanCount(userId)>0){
						throw new CxdException("您已经不可以投新手标喽");
					}
				}

				if(investMoneyd>100000){
					throw new CxdException("投资新手标不可以大于10万");
				}
			}
			
			// 输入的投资金额 大于 可投资的金额（尚未认购的金额） 抛出异常
			if (investMoneyd > remainMoney) {
				throw new CxdException("投资金额大于尚未募集的金额");
			}
			if (investMoneyd > myaccountService.getUserBalance(userId)) {
				throw new CxdException("账户金额不足");
			}

			// 创建投资订单
			InvestBase invest = new InvestBase();
			invest.setMoney(Double.parseDouble(investMoney));
			invest.setIsAutoInvest(0);
			invest.setLoanId(loanId);
			invest.setUserId(userId);
			investService.create(invest);
			invest.setStatus(InvestConstants.InvestStatus.WAIT_AFFIRM);
			bt.modify(invest);

			// 请求参数处理
			String reqContent = getReqParams(invest);
			Map<String, String> params = new HashMap<String, String>();
			 params.put("req", reqContent);
			 params.put("sign", CFCASignUtil.sign(reqContent));
			String sign = CFCASignUtil.sign(reqContent);

			 String requestData = HtmlElementUtil.createAutoSubmitForm(params,AppConstants.RequestUrl.APP_INVEST_URL,"UTF-8");
			
			// 保存操作记录
			TrusteeshipOperationBase to = new TrusteeshipOperationBase();
			to.setId(IdGenerator.randomUUID());
			to.setMarkId(invest.getId());
			to.setOperator(userId);
			to.setRequestTime(new Date());
			to.setRequestUrl(AppConstants.RequestUrl.APP_INVEST_URL);
//			to.setRequestData(MapUtil.mapToString(params));
			to.setRequestData(requestData);
			to.setStatus(TrusteeshipConstants.Status.SENDED);
			to.setType(YeePayConstants.OperationType.INVEST);
			to.setTrusteeship("yeepay");
			trusteeshipOperationService.save(to);
			Map<String, Object> mapHtml = new HashMap<String, Object>();
			mapHtml.put("reqContent", reqContent);
			mapHtml.put("isIntercept", "false");
			mapHtml.put("appRechargeBackIntercept", AppConstants.PublicConstants.APP_RECHARGE_BACK_INTERCEPT);
			mapHtml.put("sign", sign);
			mapHtml.put("actionUrl", AppConstants.RequestUrl.APP_INVEST_URL);
			mapHtml.put("callbackUrl", 	AppConstants.ResponseWebUrl.PRE_RESPONSE_URL+ YeePayConstants.OperationType.INVEST  );
			json.put("result", mapHtml);
			
			LoanBase loan1 = beanService.getLoanById(loanId);
			if(loan1.getVersion().equals(loan.getVersion())){
				loan.setVersion(loan.getVersion()+1);
				bt.modify(loan);
			}else{
				logger.error(String.format("投资版本错误:老版本号%s,新版本号%s",loan.getVersion(),loan1.getVersion())+value);
				throw new VersionException("投资版本错误,请重新投资!");
			}
			// json.put("result",
			// HtmlElementUtil.createAutoSubmitForm(params,AppConstants.RequestUrl.APP_INVEST_URL,
			// "UTF-8"));
		} catch (JSONException e) {
			throw new CxdException("JSON 解析有误");
		} catch (InsufficientBalance e) {
			throw new CxdException("账户余额不足");
		} catch (ExceedMoneyNeedRaised e) {
			throw new CxdException("投资金额大于尚未募集的金额");
		} catch (ExceedMaxAcceptableRate e) {
			throw new CxdException("竞标利率不能大于借款者可接受的最高利率！");
		} catch (ExceedDeadlineException e) {
			throw new CxdException("优惠券超过有效期！");
		} catch (UnreachedMoneyLimitException e) {
			throw new CxdException("金额未达到优惠券使用条件！");
		} catch (IllegalLoanStatusException e) {
			throw new CxdException("借款状态非法");
		} catch (NewStandardNotException e) {
			throw new CxdException("[新手专享]每人限投3次");
		}
	}

	/**
	 * 用户投资记录
	 * 
	 * @author wtj
	 * @date 2015年12月5日下午2:37:44
	 * @param json
	 * @param value
	 *            userId 用户标示 pageSize 每页条数 currentPage 第几页 static 状态
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	public void userInvests(JSONObject json, String value)
			throws InstantiationException, IllegalAccessException {
		@SuppressWarnings("unchecked")
		Map<String, Object> param = JSON.parseObject(value, HashMap.class);
		Object pageSize = param.get("pageSize");
		Object currentPage = param.get("currentPage");
		if (pageSize == null || currentPage == null) {
			throw new CxdException("分页信息不允许为空");
		}
		Object userId = param.get("userId");
		if (userId == null) {
			throw new CxdException("用户标识不能为空");
		}
		param.put("page", PageUtil.getTagPage(currentPage.toString(),pageSize.toString()));
		
		this.initUserInvests(json,rloanMapper.userInvestsListPage(param),userId.toString(),2);
	}

	
	/**
	 * 获取某天回款记录
	 * @author wtj
	 * @date 2016年5月11日下午5:07:01
	 * @param json
	 * @param value
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	public void backDateOfInvest(JSONObject json, String value)
			throws InstantiationException, IllegalAccessException {
		Map<String, String> param = MapUtil.jsonToMapString(value);
		String userId = param.get("userId");
		String date = param.get("date");
		ParamUtil.notNullParam("用户ID:"+userId,"日期:"+date);
		this.initUserInvests(json,rloanMapper.backDateOfInvest(param),userId,1);
	}
	
	/**
	 * 
	 * <一句话功能简述> <功能详细描述>
	 * @author wtj
	 * @date 2016年5月11日下午6:04:28
	 * @param json
	 * @param listMap
	 * @param userId
	 * @param isShowDes 是否显示描述 1 不显示 2显示
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	private void initUserInvests(JSONObject json,List<Map<String, Object>> listMap,String userId,int isShowDes)throws InstantiationException, IllegalAccessException {
		List<InvestBase> listInvest = BUtils.tableListMapToBean(listMap,InvestBase.class);
		List<AppLoan> appLoans = new ArrayList<AppLoan>();
		AppLoan appLoan = null;
		List<Map<String,Object>> ancunList = rloanMapper.ancunInvestList(userId.toString());
		Map<String,String> ancunMap = new HashMap<String,String>();
		for(Map<String,Object> m:ancunList){
			ancunMap.put(m.get("ID").toString(), m.get("RECORD_NO").toString());
		}
		StringBuffer sb = new StringBuffer();
		for(InvestBase invest : listInvest){
			SqlInUtil.setInStr(sb, invest.getLoanId());
		}
		Map<String,LoanBase> loanMap = new HashMap<String,LoanBase>();
		List<Map<String,Object>> loans = rloanMapper.loadLoanByInIds(sb.toString());
		for(Map<String,Object> mm:loans){
			loanMap.put(mm.get("id").toString(), BUtils.tableMapToBean(mm,LoanBase.class));
		}
		for (InvestBase invest : listInvest) {
			LoanBase loan = loanMap.get(invest.getLoanId());
			appLoan = new AppLoan(loan,bt,isShowDes);
			this.loadLoanByLoanId(loan,appLoan);
			/**
			 * 用户还款计划
			 */
			//  第三方资金托管确认中  wait_affirm 归结为投资中
			if(invest.getStatus()!=null && invest.getStatus().equals(InvestStatus.WAIT_AFFIRM)){
				invest.setStatus(InvestStatus.BID_SUCCESS);
			}
			String recordNo = ancunMap.get(invest.getId());
			appLoan.setStatus(invest.getStatus());// 用户投资状态
			appLoan.setInvestInfo(this.loadMyInvestStatistics(userId.toString(), invest.getLoanId(),invest.getId()));
			appLoan.setInvestTime(invest.getTime());
			appLoan.setInvestMoney(invest.getInvestMoney().toString());
			appLoan.setContractUrl(ProjecConfig.WEB_ROOT+"/h5c/contract?userId="+userId+"&loanId="+invest.getLoanId()+"&investId="+invest.getId());
			appLoan.setInvestId(invest.getId());
			if(StringUtils.isBlank(recordNo)){
				// 没有安存
				appLoan.setIsAnCun(AppConstants.Ancun.NO_ANCUN);
			}else{
				// 已经安存
				appLoan.setIsAnCun(AppConstants.Ancun.YES_ANCUN);
				appLoan.setAnCunUrl(MessageFormat.format(AppConstants.Ancun.ANCUN_H5_URL,recordNo));
			}
			appLoans.add(appLoan);
		}
		json.put("result", appLoans.size() == 0 ? new String[] {} : appLoans);
	}
	/**
	 * 获取已经投资金额
	 * 
	 * @param loanId
	 * @return
	 */
	public Double loadalreadyInvestMoney(String loanId) {
		String sql = "select sum(money) countNum from Invest where loan_id='"
				+ loanId + "' and (status='bid_success' or status='repaying' or status='complete' or status='recheck' or status='wait_affirm')";
		Map<String, Object> sqlMap = bt.queryMap(sql);
		if (sqlMap == null) {
			return 0d;
		} else {
			return Double.parseDouble(sqlMap.get("countNum").toString());
		}
	}

	/**
	 * 剩余可投金额
	 */
	public Integer remainMoney(LoanBase loan) {
		int remainMoney = (int)(loan.getLoanMoney() - loadalreadyInvestMoney(loan.getId()));
		if(0>remainMoney){
			remainMoney = 0;
		}
		return remainMoney;
	}

	/**
	 * 标投资进度
	 * 
	 * @author wtj
	 * @date 2015年12月5日下午3:00:21
	 * @param loan
	 * @return
	 */
	public Double loanCompletedRate(LoanBase loan) {
		return loadalreadyInvestMoney(loan.getId()) * 100 / loan.getLoanMoney();
	}

	/**
	 * 新手转向投资次数提示
	 * 
	 * @param loginUserId
	 * @return
	 */
	public String loadUserNewerLoanTip(String loginUserId) {
		String reStr = "[新手专享]每人限投3次";
		if (StringUtils.isNotBlank(loginUserId)) {
			long loadUserNewerLoanNum = PublicConstants.NEWER_COUNT_LIMIT
					- loadUserNewerLoanNum(loginUserId);
			if (loadUserNewerLoanNum <= 0) {
				reStr = "您已不能投[新手专享]喽";
			} else {
				reStr = "您还可投" + loadUserNewerLoanNum + "次[新手专享]";
			}
		}
		return reStr;
	}
	/**
	 * 用户投资新手标次数
	 * @author wtj
	 * @date 2016年2月29日下午6:37:30
	 * @param userId
	 * @return
	 */
	public int getUserNewLoanCount(Object userId){
		int count = bt.queryForInt("select count(distinct loan.id) from Invest invest , Loan loan "
				+ "where invest.status!='cancel' and invest.loan_id = loan.id "
				+ "and loan.deadline=8 and loan.rate=0.2 and invest.user_id ='"+userId+"' and invest.time >'"+NEWER_LOAN_BEGIN+"'");
		return count;
	}
	/**
	 * 获取用户投资新手标次数
	 * 
	 * @param loanId
	 * @return
	 */
	public long loadUserNewerLoanNum(String loginUserId) {
		long isCast = 0;
		if (isCanInvest(loginUserId)) {
//			String sql = "SELECT count(distinct loan_id) countNum FROM INVEST inv , LOAN lo where inv.STATUS!='cancel' and inv.LOAN_ID = lo.id "
//					+ "and lo.DEADLINE=8 and lo.rate=0.2 and inv.USER_ID ='"
//					+ loginUserId
//					+ "'  and lo.COMMIT_TIME >'"
//					+ PublicConstants.NEWER_BEGIN_TIME + "'";
//			Map<String, Object> sqlMap = bt.queryMap(sql);
//			if (sqlMap != null) {
//				isCast = Long.parseLong(sqlMap.get("countNum").toString());
//			}
			isCast = getUserNewLoanCount(loginUserId);
		}
		return isCast;
	}

	/**
	 * 判断项目是否募集完成
	 * 
	 * @author wtj
	 * @date 2015年12月5日下午4:42:43
	 * @param loan
	 */
	@Transactional(propagation = Propagation.REQUIRED)
	public void dealRaiseComplete(LoanBase loan) {
		if (remainMoney(loan) == 0) {
			// 项目募集完成
			loan.setStatus(LoanConstants.LoanStatus.RECHECK);
			bt.modify(loan);
		}
	}

	private String getReqParams(InvestBase invest) throws CxdException {
		String loanId = invest.getLoanId();
		LoanBase loanBase = beanService.getLoanById(loanId);

		StringBuffer content = new StringBuffer();
		content.append("<?xml version='1.0' encoding='utf-8'?>");
		// 商户编号:商户在易宝唯一标识
		content.append("<request platformNo='"
				+ YeePayConstants.Config.MER_CODE + "'>");
		// 商户平台会员标识:会员在商户平台唯一标识
		content.append("<platformUserNo>" + invest.getUserId()
				+ "</platformUserNo>");
		// 请求流水号:接入方必须保证参数内的 requestNo 全局唯一，并且需要保存，留待后续业务使用
		content.append("<requestNo>" + YeePayConstants.RequestNoPre.INVEST
				+ invest.getId() + "</requestNo>");
		// 标的号:标识要自动还款的标的号
		content.append("<orderNo>" + invest.getLoanId() + "</orderNo>");
		// 标的金额
		content.append("<transferAmount>" + loanBase.getLoanMoney()
				+ "</transferAmount>");
		// 目标会员编号
		content.append("<targetPlatformUserNo>" + loanBase.getUserId()
				+ "</targetPlatformUserNo>");
		// 冻结金额
		content.append("<paymentAmount>" + invest.getMoney()
				+ "</paymentAmount>");
		Date date = DateUtil.addMinute(new Date(), 10);
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		content.append("<expired>" + sdf.format(date) + "</expired>");
		// 页面回跳URL
		content.append("<callbackUrl>"
				+ AppConstants.ResponseWebUrl.PRE_RESPONSE_URL
				+ YeePayConstants.OperationType.INVEST + "</callbackUrl>");
		// 服务器通知 URL:服务器通知 URL
		content.append("<notifyUrl>"
				+ AppConstants.ResponseS2SUrl.PRE_RESPONSE_URL
				+ YeePayConstants.OperationType.INVEST + "</notifyUrl>");
		// 提现金额:如果传入此，将使用该金额提现且用户将不可更改
		content.append("</request>");
		return content.toString();
	}

	/**
	 * 用户投资项目还款计划
	 * 
	 * @author wtj
	 * @date 2015年12月8日下午3:40:50
	 * @param json
	 * @param value
	 */
	public void repayPlan(JSONObject json, String value) {
		Map<String, String> param = MapUtil.jsonToMapString(value);
		String loanId = param.get("loanId");
		String userId = param.get("userId");
		ParamUtil.notNullParam("用户名:" + userId, "借款ID:" + loanId);
		;
		String sql = "SELECT ir.* FROM INVEST_REPAY ir WHERE INVEST_ID in ( select t.id from Invest t where  user_id='"
				+ userId.trim()
				+ "' and  loan_id='"
				+ loanId.toString()
				+ "') ORDER BY repay_day asc";

		List<InvestRepayBase> list = bt.queryListBean(sql,
				InvestRepayBase.class);
		for (InvestRepayBase ir : list) {
			ir.setStatusType(ir.getStatus());
			ir.setStatus(dictService.getValue("repay_status", ir.getStatus()));
			ir.setTotalMoney(ArithUtil.round(ArithUtil.add(Double.parseDouble(ir.getCorpus()),Double.parseDouble(ir.getInterest())),2)+"");
		}
		json.put("result", list.size() == 0 ? new String[] {} : list);
	}

	/**
	 * 我的投资统计
	 * 
	 * @author wtj
	 * @date 2015年12月19日上午11:53:13
	 * @return
	 */
	public InvestInfo loadMyInvestStatistics(String userId, String loanId,String investId) {
		String sql = "SELECT ir.* FROM INVEST_REPAY ir WHERE INVEST_ID='"+investId+"' ORDER BY repay_day asc";
//				+ " in ( select t.id from Invest t where  user_id='"
//				+ userId.trim()
//				+ "' and  loan_id='"
//				+ loanId.toString()
//				+ "') "
// 				+ "and NOW() < ir.repay_day ORDER BY repay_day asc limit 0,1";
		List<InvestRepayBase> brb = bt.queryListBean(sql, InvestRepayBase.class);
		InvestInfo iiBean = new InvestInfo();
		// 待收本息
		Double waitingCollectMoneyDouble = 0d;
		// 下一期待收利息
		Double nextCollectMoney = 0d;
		Date nextRepayDate = null;
		// 下一期标示
		int nextFlag = 0;
		Double totalInterest = 0d;
		Double totalAmount = 0d;
		for (InvestRepayBase irb : brb) {
			if (new Date().getTime() < irb.getRepayDay().getTime() || irb.getStatus().equals(InvestStatus.REPAYING)) {
				if (nextFlag == 0) {
					waitingCollectMoneyDouble = ArithUtil.add(Double.parseDouble(irb.getCorpus()),Double.parseDouble(irb.getInterest()),waitingCollectMoneyDouble);
					nextCollectMoney = ArithUtil.add(Double.parseDouble(irb.getCorpus()),Double.parseDouble(irb.getInterest()));
					nextRepayDate = irb.getRepayDay();
					nextFlag++;
				}
			}
			totalInterest = ArithUtil.add(Double.parseDouble(irb.getInterest()), totalInterest);
			totalAmount = ArithUtil.add(Double.parseDouble(irb.getCorpus()),Double.parseDouble(irb.getInterest()), totalAmount);
		}
		iiBean.setNextCollectMoney(nextCollectMoney + "");
		iiBean.setWaitingCollectMoney(waitingCollectMoneyDouble + "");
		iiBean.setNextRepayDate(nextRepayDate==null?"无":DateUtil.dateToString(nextRepayDate, DateStyle.YYYY_MM_DD.getValue()));
		iiBean.setTotalInterest(totalInterest.toString());
		iiBean.setTotalAmount(totalAmount.toString());
		return iiBean;
	}

	/**
	 * 项目投资记录
	 * 
	 * @author wtj
	 * @date 2015年12月8日下午3:56:57
	 * @param json
	 * @param value
	 */
	public void investRecords(JSONObject json, String value)
			throws InstantiationException, IllegalAccessException {
		Map<String, Object> param = MapUtil.jsonToMap(value);
		Object loanId = param.get("loanId");
		Object pageSize = param.get("pageSize");
		Object currentPage = param.get("currentPage");
		if (loanId == null || pageSize == null || currentPage == null) {
			throw new CxdException("请求参数有空数据");
		}
		param.put("page", PageUtil.getTagPage(currentPage.toString(),
				pageSize.toString()));
		List<InvestBase> listBean = BUtils.tableListMapToBean(
				rinvestMapper.investListPage(param), InvestBase.class);
		List<InvestRecord> irList = new ArrayList<InvestRecord>();
		InvestRecord ir = null;
		for (InvestBase i : listBean) {
			ir = new InvestRecord();
			ir.setInvestUser(getInvestUserName(i.getUserId()));
			ir.setMoney(NumberUtil.getNumber(i.getInvestMoney()));
			ir.setStatus(dictService.getValue("invest_status", i.getStatus()));
			ir.setStatusType(i.getStatus().toString());
			ir.setTime(DateUtil.dateToString(i.getTime(),DateStyle.YYYY_MM_DD_HH_MM_SS_EN.getValue()));
			irList.add(ir);
		}
		json.put("result", irList.size() == 0 ? new String[] {} : irList);
	}

	public String getInvestUserName(String userId){
		int len = userId.length();
		String investUserName;
		switch (len) {
		case 1:
			investUserName = userId+"***";
			break;
		case 2:
			investUserName = userId+"***";
			break;
		case 3:
			investUserName = userId.substring(0,2)+"***"+userId.substring(2);
			break;
		case 4:
			investUserName = userId.substring(0,2)+"***"+userId.substring(2);
			break;
		default:
			investUserName = userId.substring(0,2)+"***"+userId.substring(len-3);
			break;
		}
		return investUserName;
	}
	public Map<String,Object> loadLoanContract(String loanId){
		return rloanMapper.loadLoanMap(loanId);
	}
	/**
	 * 项目协议
	 * 
	 * @author wtj
	 * @date 2015年12月9日下午1:25:39
	 * @param json
	 * @param value
	 */
	public String contract(String userId,String loanId,String investId,Map<String, Object> loan ) {
		String contractContent = null;

		try {
			Map<String,String> param = new HashMap<String,String>();
			param.put("loanId",loanId);
			param.put("userId",userId);
			param.put("investId",investId);
			ParamUtil.notNullParam("借款ID:" + loanId, "用户名:" + userId);
			if (LoanStatus.RAISING.equals(loan.get("STATUS"))
					|| LoanStatus.RECHECK.equals(loan.get("STATUS"))
					|| LoanStatus.CANCEL.equals(loan.get("STATUS"))) {
				//	json.put("result", new String[] {});
				//	json.put("status", 500);
				return "合同还未生成，请等待";
			}

			Element table = Jsoup
					.parseBodyFragment("<table border='1' style='margin: 0px auto; border-collapse: collapse; border: 1px solid rgb(0, 0, 0); width: 90%; ' class='cur'>"
							+ "<tbody><tr class='firstRow'><td style='text-align:center;'>姓名</td>"
							+ "<td style='text-align:center;'>投标来源</td>"
							+ "<td style='text-align:center;'>借出金额</td>"
							+ "<td style='text-align:center;'>借款期限</td>"
							+ "<td style='text-align:center;'>应收利息</td>"
							+ "</tr>"
							+ "</tbody>"
							+ "</table>");
			Element tbody = table.getElementsByTag("tbody").first();

			List<Map<String, Object>> listMap = rinvestMapper.investByInvestId(param);
			UserBase user = beanService.getUserById(userId);
			if (user == null) {
				//	json.put("result", new String[] {});
				//	json.put("status", 500);
				return "用户未发现";
			}
			Loan loanTools = new Loan(loanId);
			RepayRoadmap loanRepayRoadmap = loanTools.getRepayRoadmap();
			for (Map<String, Object> invest : listMap) {
				int deadline = (Integer) loan.get("DEADLINE");

				String repayTimeUnit = invest.get("REPAY_TIME_UNIT").toString();
				Invest investTools = new Invest(invest.get("ID").toString());
				RepayRoadmap repayRoadmap = investTools.getRepayRoadmap();
				tbody.append("<tr><td style='text-align:center;'>"
						+ user.getRealname()
						+ "</td><td style='text-align:center;'>"
						+ (invest.get("IS_AUTO_INVEST").equals("1") ? "自动投标": "手动投标")
						+ "</td><td style='text-align:center;'>"
						+ repayRoadmap.getRepayCorpus()
						+ "</td><td style='text-align:center;'>"
						+ deadline* Integer.parseInt(loan.get("REPAY_TIME_PERIOD").toString())
						+ "("+ dictService.getValue("repay_unit", repayTimeUnit) + ")</td>"
						+ "<td style='text-align:center;'>"+ repayRoadmap.getRepayInterest() + "</td></tr>");
			}
//			tbody.append("<tr><td style='text-align:center;'>总计</td><td></td><td style='text-align:center;'>"
//					+ loanRepayRoadmap.getRepayCorpus()
//					+ "</td><td></td><td style='text-align:center;'>"
//					+ loanRepayRoadmap.getRepayInterest() + "</td></tr>");

			NodeBase node = bt.queryBean("NODE", "ID",
					loan.get("CONTRACT_TYPE"), NodeBase.class);
			NodeBase guaranteeCompanyName = null;
			if (loan.get("GUARANTEE_COMPANY_NAME") != null
					&& !"".equals(loan.get("GUARANTEE_COMPANY_NAME"))) {
				guaranteeCompanyName = bt.queryBean("NODE", "ID",
						loan.get("GUARANTEE_COMPANY_NAME"), NodeBase.class);
			}
			if (contractContent == null) {
				Date endDate = null;
				Date interestBeginTime = (Date) loan.get("INTEREST_BEGIN_TIME");
				int deadline = (Integer) loan.get("DEADLINE");
				if (RepayConstants.RepayUnit.DAY.equals(loan
						.get("REPAY_TIME_UNIT"))) {
					endDate = DateUtil.addDay(interestBeginTime, deadline);
				} else if (RepayConstants.RepayUnit.MONTH.equals(loan
						.get("REPAY_TIME_UNIT"))) {
					endDate = DateUtil.addMonth(interestBeginTime, deadline);
				}
				NodeBodyBase nodeBody = bt.queryBean("NODE_BODY", "ID",node.getBody(), NodeBodyBase.class);
				contractContent = nodeBody.getBody();
				String idCard="";
				if(loan.get("ID_CARD")!=null){
					idCard = CxdStringUtil.strAddStar(loan.get("ID_CARD").toString(), 3, 3, 5);
				}
				contractContent = contractContent
						.replace("#{loanId}", loan.get("ID").toString())
						.replace("#{actualMoney}", loan.get("MONEY").toString())
						.replace("#{investList}", table.outerHtml())
						.replace("#{interest}",
								loanRepayRoadmap.getRepayInterest().toString())
						.replace("#{loanerRealname}",
								loan.get("REALNAME").toString())
						.replace("#{loanerIdCard}",idCard)
						.replace("#{loanerUsername}",
								loan.get("USERNAME").toString())
						.replace(
								"#{guaranteeCompanyName}",
								guaranteeCompanyName == null ? ""
										: guaranteeCompanyName.getTitle())
						.replace("#{giveMoneyDate}",
								loan.get("GIVE_MONEY_TIME")==null?"":DateUtil.stringToString(loan.get("GIVE_MONEY_TIME").toString(),
										DateStyle.YYYY_MM_DD_CN.getValue()))
						.replace(
								"#{rate}",
								String.valueOf(ArithUtil.round(
										(Double) loan.get("RATE") * 100, 2)))
						.replace(
								"#{deadline}",
								String.valueOf(loanRepayRoadmap
										.getRepayPeriod()))
						.replace("#{interestBeginTime}",
								loan.get("INTEREST_BEGIN_TIME").toString())
						// FIXME:需要根据借款类型，来计算借款到期日
						.replace(
								"#{interestEndTime}",
								DateUtil.dateToString(endDate,
										DateStyle.YYYY_MM_DD_CN.getValue()))
						.replace("#{repayAllMoney}",
								loanRepayRoadmap.getRepayMoney().toString())
						// FIXME:需要根据借款类型，来显示还款日
						.replace(
								"#{repayDay}",loanTools.getLoanRepays()==null?"":
								String.valueOf(DateUtil.getInteger(loanTools
										.getLoanRepays().get(0).getRepayDay(),
										Calendar.DATE)))
						.replace("#{investTransferList}", "债权转让列表")
						.replace("70%", "90%");
			}
			//	json.put("result", contractContent);
		} catch (JSONException e) {
			//	json.put("msg", "JSON解析有误");
			//	json.put("status", "404");
			return "合同生成失败,请联系管理员";
		}
		return contractContent;
	}
	
	/**
	 * 是否可以投资
	 * @author wtj
	 * @date 2016年3月7日下午5:52:09
	 * @param loginUserId
	 * @return
	 */
	public Boolean isCanInvest(String loginUserId){
		if(!loginUserId.equals("cxzdc")&&!loginUserId.equals("xueyanxueyan")&&!loginUserId.equals("wlsnow")){
			return true;
		}else{
			return false;
		}
	}
	
	/**
	 * 网贷之家获取借款数据
	 * <一句话功能简述> <功能详细描述>
	 * @author wtj
	 * @date 2016年5月4日上午11:43:39
	 * @param json
	 * @param param
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	public void wdzj_loans(JSONObject json,Map<String, Object> param)
			throws InstantiationException, IllegalAccessException {
		Object pageSize = param.get("pageSize");
		Object currentPage = param.get("currentPage");
		if (pageSize == null || currentPage == null) {
			throw new CxdException("分页信息不能为空");
		}
		TagPage page = PageUtil.getTagPage(currentPage.toString(),pageSize.toString());
		param.put("page", page);
		
		List<Map<String,Object>> list = rloanMapper.wdzjLoansListPage(param);
		
		List<WdzjLoan> wdzjLoans = new ArrayList<WdzjLoan>();
		
		Double totalAmount = 0d;
		for(Map<String,Object> m:list){
			
			String loanId = m.get("id").toString();
//			Double loanMoney = (Double)m.get("loan_money");
//			totalAmount += loanMoney;
			// 实际融资额度
			Double amount = loadalreadyInvestMoney(loanId);
			totalAmount += amount;
					
			LoanTypeBase loanType = this.queryLoanTypeByType(m.get("type").toString());
			
			
			WdzjLoan wl = new WdzjLoan();
			wl.setProjectId(loanId);
			wl.setTitle(m.get("name").toString());
			wl.setAmount(ArithUtil.round(Double.parseDouble(amount.toString()),2)+"");
			wl.setSchedule("100");//(amount * 100/loanMoney)+""
			wl.setInterestRate(Double.parseDouble(m.get("rate").toString())*100+"%");
			wl.setDeadline(Integer.parseInt(m.get("deadline").toString()));
			if(RepayConstants.RepayUnit.DAY.equals(loanType.getRepayTimeUnit())){
				wl.setDeadlineUnit("天");
				wl.setType("理财计划");
			}else{
				wl.setDeadlineUnit("月");
				wl.setType("抵押标");
			}
			wl.setReward(0d);
			wl.setRepaymentType(getRepaymentType(loanType));
			List<WdzjInvest> investList = this.wdzjLoanInvests(loanId);
			wl.setSubscribes(investList);
			wl.setUserName(m.get("user_id").toString());
			wl.setLoanUrl(MessageFormat.format(AppConstants.PublicConstants.WWW_LOAN_URL,loanId));
			wl.setSuccessTime(DateUtil.stringToString(m.get("give_money_time").toString(),DateStyle.YYYY_MM_DD_HH_MM_SS.getValue()));
//			if(investList!=null && investList.size()>0){
//				wl.setSuccessTime(investList.get(investList.size()-1).getAddDate());
//			}
			wl.setPublishTime(DateUtil.stringToString(m.get("commit_time").toString(),DateStyle.YYYY_MM_DD_HH_MM_SS.getValue()));
			wdzjLoans.add(wl);
		}
		
		json.put("borrowList", wdzjLoans);
		json.put("totalPage", page.getTotalPage());
		json.put("currentPage", currentPage);
		json.put("totalCount", wdzjLoans.size());
		json.put("totalAmount", ArithUtil.round(totalAmount,2)+"");
	}

	/**
	 * 网贷之家还款方式
	 * @author wtj
	 * @date 2016年5月4日下午3:35:11
	 * @param loanType
	 * @return
	 */
	public int getRepaymentType(LoanTypeBase loanType){
		if(loanType.getId().equals("loan_type_1")|| loanType.getId().equals("loan_type_3")){
			return 9;
		}else if(loanType.getId().equals("loan_type_4")|| loanType.getId().equals("loan_type_5")){
			return 1;
		}else{ 
			//if(loanType.getId().equals("loan_type_2")){
			return 5;
		}
	}
	
	/**
	 * 获取项目类型信息
	 * @author wtj
	 * @date 2016年5月4日下午5:10:58
	 * @param loanType
	 * @return
	 */
	public LoanTypeBase queryLoanTypeByType(String loanType){
		return BUtils.tableMapToBean(rloanMapper.queryLoanTypeByType(loanType), LoanTypeBase.class); 
	}
	/**
	 * 网贷之家获取借款投资记录
	 * @author wtj
	 * @date 2016年5月4日下午4:26:35
	 * @param loanId
	 * @return
	 */
	private List<WdzjInvest> wdzjLoanInvests(String loanId){
		List<WdzjInvest> investList = new ArrayList<WdzjInvest>();
		List<Map<String,Object>> listMap = this.queryLoanInvestSuccess(loanId);
		for(Map<String,Object> map:listMap){
			WdzjInvest wi = new WdzjInvest();
			wi.setSubscribeUserName(map.get("user_id").toString());
			wi.setAmount(ArithUtil.round(Double.parseDouble(map.get("money").toString()),2)+"");
			wi.setAddDate(DateUtil.stringToString(map.get("time").toString(),DateStyle.YYYY_MM_DD_HH_MM_SS.getValue()) );
			wi.setValidAmount(ArithUtil.round(Double.parseDouble(map.get("money").toString()),2)+"");
			wi.setStatus(1);
			wi.setType(0);
			investList.add(wi);
		}
		return investList;
	}
	
	/**
	 * 根据借款ID获取投资成功的记录
	 * <一句话功能简述> <功能详细描述>
	 * @author wtj
	 * @date 2016年5月4日下午3:27:45
	 * @param loanId
	 * @return
	 */
	public List<Map<String,Object>> queryLoanInvestSuccess(String loanId){
		return rloanMapper.queryLoanInvestSuccess(loanId);
	}
}
